package configs

import (
    "crypto/aes"
    "crypto/cipher"
	"crypto/sha256"
	"encoding/base64"
	"net/http"
    "fmt"
    "log"
    "os"
    "time"
    "strconv"
    "strings"
    "crypto/hmac"
    "encoding/hex"
    "github.com/denisbrodbeck/machineid"
    "github.com/gin-gonic/gin"
)


var (
    Jmkey           = "7b03405999897144946412b2e49a2256"
    snqz            = "Ydzx-Kzh"
    ganfangID       = "df3d28f428bd4967b97c6e9905500465"  // 官方硬件ID
    GanfangSN       = "1/ZbvYoCd+zkCN/s70huPcvsUn9tQCeBp2MkQct6EdE3/ukxgWzPmLXi97lilBm0qHUU8QbCI9McI0aSAgiQVg==" // 官方序列号
)

type Sndata struct {
    Password string `json:"password"`
    Sysid    string `json:"sysid"`
    Day      int    `json:"day"`
}

// 校验请求数据
func ValidateSNRequestData(data *Sndata) error {
    if data.Password != "Love3240" {
        return fmt.Errorf("密码错误")
    }
    if data.Sysid == "" {
        return fmt.Errorf("硬件ID为空")
    }
    if data.Day < 1 {
        return fmt.Errorf("授权天数为空")
    }
    return nil
}

// 生成初次序列号: 密钥为空或非官方主机但密钥是官方主机
func IsStart() {
    currentHardwareID := Getsysid()
    sn := Config.GetString("server.sn")
    if sn == "" || (currentHardwareID != ganfangID && sn == GanfangSN) {
        serialNumber := GenerateSerialNumber(currentHardwareID, 30)
        if err := UpdateEnvFile("server.sn", serialNumber); err != nil {
            log.Fatal("无法写入配置文件:", err)
        }
        fmt.Println("已将序列号写入配置文件")
    }
    CheckSNValidity()
}

//获取硬件id
func Getsysid() string {
    currentHardwareID, err := machineid.ID()
    if err != nil {
        log.Fatal("无法获取设备硬件信息：", err)
    }
    return currentHardwareID
}

// 检查序列号有效性
func CheckSNValidity() {
    currentHardwareID := Getsysid()
    serialNumber := Config.GetString("server.sn")
    if currentHardwareID != ganfangID && !ValidateSerialNumber(serialNumber, currentHardwareID) {
        log.Println("服务器未授权，请联系供应商获取授权。")
        log.Println("您的硬件 ID 是:", currentHardwareID)
        fmt.Println("按回车键退出程序...")
        fmt.Scanln()
        os.Exit(0)
    }
}

// 生成序列号
func GenerateSerialNumber(hardwareID string, day int) string {
    expiration := time.Now().AddDate(0, 0, day)
    timestamp := expiration.Unix()
    combinedInfo := snqz + hardwareID
    encodedInfo := AesSimpleEncrypt(fmt.Sprintf("%s|%d", combinedInfo, timestamp), Jmkey)
    return encodedInfo
}

// 校验序列号并比对硬件ID和时间戳
func ValidateSerialNumber(serialNumber, currentHardwareID string) bool {
    if currentHardwareID == ganfangID {
        return true // 官方主机不检查
    }
    decodedInfo := AesSimpleDecrypt(serialNumber, Jmkey)
    if len(decodedInfo) < len(snqz)+len(currentHardwareID)+11 {
        fmt.Println("密钥错误，请检查密钥是否正确")
        return false
    }
    infoParts := strings.Split(decodedInfo, "|")
    if len(infoParts) != 2 {
        fmt.Println("密钥格式错误")
        return false
    }
    timestampStr := infoParts[1]
    timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
    if err != nil {
        fmt.Println("时间戳解析错误")
        return false
    }
    expiration := time.Unix(timestamp, 0)
    if time.Now().After(expiration) {
        fmt.Println("序列号已过期")
        return false
    }
    return infoParts[0][len(snqz):] == currentHardwareID
}

// 生成IV
func generateIV(key []byte) []byte {
	hasher := sha256.New()
	hasher.Write(key)
	return hasher.Sum(nil)[:16] // 使用前16字节作为IV
}

// 加密（ZeroPadding填充）
func AesSimpleEncrypt(plainText, mykey string) string {
	key := []byte(mykey)
	iv := generateIV(key)
	block, _ := aes.NewCipher(key)
	// 填充数据
	plainTextBytes := []byte(plainText)
	plainTextBytes = addZeroPadding(plainTextBytes)
	// 加密
	cipherText := make([]byte, len(plainTextBytes))
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(cipherText, plainTextBytes)
	// 返回base64编码后的加密数据
	return base64.StdEncoding.EncodeToString(cipherText)
}

// 添加ZeroPadding
func addZeroPadding(data []byte) []byte {
	blockSize := aes.BlockSize
	paddingLen := blockSize - len(data)%blockSize
	if paddingLen == blockSize {
		return data
	}
	padding := make([]byte, paddingLen)
	data = append(data, padding...)
	return data
}

// 解密（适配前端CryptoJS的CBC模式+ZeroPadding）
func AesSimpleDecrypt(cryptoText, mykey string) string {
	key := []byte(mykey)
	if len(key) > 32 {
		key = key[:32]
	}
	iv := generateIV(key)
	block, _ := aes.NewCipher(key)
	// Base64解码加密后的密文
	ciphertext, _ := base64.StdEncoding.DecodeString(cryptoText)
	if len(ciphertext)%aes.BlockSize != 0 {
		return ""
	}
	// 解密
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(ciphertext, ciphertext)
	// 去除ZeroPadding
	return string(removeZeroPadding(ciphertext))
}

// 移除ZeroPadding
func removeZeroPadding(data []byte) []byte {
	for i := len(data) - 1; i >= 0; i-- {
		if data[i] != 0 {
			return data[:i+1]
		}
	}
	return data
}


// 在线更新认证中间件------------------
func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取认证信息
        sn := c.GetHeader("X-SN")
        hwID := c.GetHeader("X-HWID")
        // 基础头校验
        if sn == "" || hwID == "" {
            abortAuthError(c, "缺失认证头")
            return
        }
        // 序列号验证
        if !ValidateSerialNumber(sn, hwID) {
            abortAuthError(c, "无效序列号")
            return
        }
        // 动态令牌验证（仅对下载接口）
        token := c.Query("t")
        if !validateDownloadToken(hwID, token) {
            abortAuthError(c, "无效下载令牌")
            return
        }
        c.Next()
    }
}

// 统一错误处理
func abortAuthError(c *gin.Context, msg string) {
    log.Printf("[Auth] 客户端:%s | 路径:%s | 错误:%s", c.ClientIP(), c.Request.URL.Path, msg)
    c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
        "code":    "AUTH_FAILED",
        "message": msg,
    })
}

// 动态令牌生成验证逻辑
func validateDownloadToken(hwID, token string) bool {
    now := time.Now().Unix()
    // 允许2分钟时钟偏差
    for ts := now - 120; ts <= now + 120; ts += 300 {
        expectedTS := ts / 300
        expected := generateToken(hwID, expectedTS)
        if hmac.Equal([]byte(token), []byte(expected)) {
            return true
        }
    }
    return false
}

func generateToken(hwID string, ts int64) string {
    raw := fmt.Sprintf("%s|%d|300", hwID, ts) // 格式必须一致
    h := hmac.New(sha256.New, []byte(Jmkey))
    h.Write([]byte(raw))
    token := hex.EncodeToString(h.Sum(nil))
    log.Printf("[Server] 预期令牌: %s", token)
    return token
}